package com.yupi.springbootinit.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.mapper.*;
import com.yupi.springbootinit.model.dto.qa.QualityInspectionRequest;
import com.yupi.springbootinit.model.entity.*;
import com.yupi.springbootinit.model.enums.StepEvent;
import com.yupi.springbootinit.model.enums.StepStatus;
import com.yupi.springbootinit.model.vo.qa.QualityInspectionDetailVO;
import com.yupi.springbootinit.service.*;
import com.yupi.springbootinit.service.workflow.WorkflowTaskCreationService;
import com.yupi.springbootinit.service.workflow.WorkflowTaskOperationService;
import com.yupi.springbootinit.statemachine.step.StepStateMachine;
import com.yupi.springbootinit.statemachine.step.StepTransitionContext;
import com.yupi.springbootinit.statemachine.step.impl.DefaultStepStateMachine;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 品质检验服务实现
 */
@Slf4j
@Service
public class QualityInspectionServiceImpl implements QualityInspectionService {

    @Resource
    private ProcessBatchStepMapper processBatchStepMapper;

    @Resource
    private WorkflowTaskMapper workflowTaskMapper;

    @Resource
    private WorkflowTaskService workflowTaskService;

    @Resource
    private ProcessBatchService processBatchService;

    @Resource
    private WorkflowTaskOperationService workflowTaskOperationService;

    @Resource
    private OutboxService outboxService;

    @Resource
    private ProcessSheetStepMapper processSheetStepMapper;

    @Resource
    private ProcessBatchMapper processBatchMapper;

    @Resource
    private ProcessSheetBatchMapper processSheetBatchMapper;

    @Resource
    private ProcessSheetBatchProductMapper processSheetBatchProductMapper;

    @Resource
    private ProcessSheetProductMapper processSheetProductMapper;

    @Resource
    private QualityInspectionRecordService qualityInspectionRecordService;

    @Resource
    private WorkflowTaskCreationService taskCreationService;

    @Resource
    private QualityInspectionRecordMapper qualityInspectionRecordMapper;

    @Resource
    private ProductionOperationRecordMapper productionOperationRecordMapper;

    private final StepStateMachine stepStateMachine = new DefaultStepStateMachine();

    @Override
    public QualityInspectionDetailVO getInspectionDetail(Long taskId, Long userId) {
        if (taskId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "任务ID不能为空");
        }

        log.info("查询质检任务详情: taskId={}, userId={}", taskId, userId);

        // 1. 先尝试作为任务ID查询
        WorkflowTask task = workflowTaskMapper.selectById(taskId);

        // 2.   如果查不到，尝试作为工序ID查询对应的质检任务
        if (task == null) {
            log.info("未找到任务记录，尝试作为工序ID查询: possibleStepId={}", taskId);

            LambdaQueryWrapper<WorkflowTask> qw = new LambdaQueryWrapper<>();
            qw.eq(WorkflowTask::getBizType, "PROCESS_BATCH_STEP").eq(WorkflowTask::getBizId, taskId).eq(WorkflowTask::getTaskType, "QUALITY_INSPECTION").eq(WorkflowTask::getIsDelete, 0).orderByDesc(WorkflowTask::getCreateTime).last("LIMIT 1");

            task = workflowTaskMapper.selectOne(qw);

            if (task != null) {
                log.info("通过工序ID找到质检任务: stepId={}, taskId={}", taskId, task.getId());
            }
        }

        // 3. 如果还是查不到，抛出异常
        if (task == null) {
            log.error("质检任务不存在: id={}", taskId);
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "质检任务不存在，请确认任务ID是否正确（ID:" + taskId + "）。如果是从任务列表进入的，请刷新页面后重试。");
        }

        if (task.getIsDelete() == 1) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "任务已被删除");
        }

        // 4. 校验任务类型
        if (!"QUALITY_INSPECTION".equals(task.getTaskType())) {
            log.error("任务类型错误: taskId={}, taskType={}, expected=QUALITY_INSPECTION", task.getId(), task.getTaskType());
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "任务类型错误，不是质检任务（实际类型:" + task.getTaskType() + "）");
        }

        log.info("查询到质检任务: taskId={}, taskType={}, stepId={}", task.getId(), task.getTaskType(), task.getBizId());

        // 5. 查询工序信息（bizId = stepId）
        Long stepId = task.getBizId();
        ProcessBatchStep step = processBatchStepMapper.selectById(stepId);
        if (step == null || step.getIsDeleted() == 1) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "工序不存在");
        }

        // 6. 查询工艺单工序（检验要求）
        ProcessSheetStep sheetStep = null;
        if (step.getProcessSheetStepId() != null) {
            sheetStep = processSheetStepMapper.selectById(step.getProcessSheetStepId());
        }

        // 7. 查询批次信息（订单、设备）
        ProcessBatch batch = processBatchMapper.selectById(step.getBatchId());
        if (batch == null || batch.getIsDeleted() == 1) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "批次不存在");
        }

        // 8. 查询操作员信息
        String operatorName = getOperatorName(stepId);

        // 9. 查询历史质检记录
        List<QualityInspectionRecord> historyRecords = qualityInspectionRecordMapper.selectList(new LambdaQueryWrapper<QualityInspectionRecord>().eq(QualityInspectionRecord::getStepId, stepId).orderByDesc(QualityInspectionRecord::getInspectionTime));

        // 10. 组装 VO
        QualityInspectionDetailVO vo = new QualityInspectionDetailVO();

        // ========== 任务基本信息 ==========
        vo.setTaskId(String.valueOf(task.getId()));
        vo.setTaskTitle(task.getTaskTitle());
        vo.setTaskStatus(task.getTaskStatus());
        vo.setTaskStatusName(getTaskStatusName(task.getTaskStatus()));
        vo.setPriority(task.getPriority());
        vo.setPriorityName(getPriorityName(task.getPriority()));
        vo.setExpectedCompleteTime(task.getExpectedCompleteTime());
        vo.setCreateTime(task.getCreateTime());
        vo.setIsClaimed(task.getClaimedBy() != null);
        vo.setClaimedByName(task.getClaimedByName());

        // ========== 工序信息 ==========
        QualityInspectionDetailVO.StepInfo stepInfo = new QualityInspectionDetailVO.StepInfo();
        stepInfo.setStepId(String.valueOf(step.getId()));
        stepInfo.setSequenceNo(step.getSequenceNo());
        stepInfo.setOperationName(step.getOperationName());
        stepInfo.setOperationCode(step.getOperationCode());
        stepInfo.setActualStart(step.getActualStart());
        stepInfo.setActualEnd(step.getActualEnd());
        stepInfo.setExpectedDurationMinutes(step.getExpectedDurationMinutes());
        stepInfo.setOperatorName(operatorName);
        stepInfo.setStatus(step.getStatus());
        stepInfo.setStatusName(getStepStatusName(step.getStatus()));

        // 计算实际工时
        if (step.getActualStart() != null && step.getActualEnd() != null) {
            long actualMinutes = java.time.Duration.between(step.getActualStart(), step.getActualEnd()).toMinutes();
            stepInfo.setActualDurationMinutes(actualMinutes);
        }

        // 工艺要求（来自工艺单）
        if (sheetStep != null) {
            stepInfo.setProcessRequirement(sheetStep.getProcessRequirement());
            stepInfo.setInspectionMethod(sheetStep.getInspectionMethod());
            stepInfo.setInspectionCriteria(sheetStep.getInspectionCriteria());
            stepInfo.setIsInspectionRequired(sheetStep.getIsInspectionRequired());
        }

        vo.setStepInfo(stepInfo);

        // ========== 订单信息 ==========
        QualityInspectionDetailVO.OrderInfo orderInfo = new QualityInspectionDetailVO.OrderInfo();
        orderInfo.setOrderNumber(batch.getOrderNumber());
        orderInfo.setProductName(batch.getProductName());
        orderInfo.setBatchCode(batch.getBatchCode());
        orderInfo.setQuantity(batch.getQuantity());
        orderInfo.setOrderType(batch.getOrderType());
        orderInfo.setOrderTypeName(getOrderTypeName(batch.getOrderType()));

// ✅ 查询批次序号
        if (batch.getBatchPlanId() != null) {
            try {
                ProcessSheetBatch batchPlan = processSheetBatchMapper.selectById(batch.getBatchPlanId());
                if (batchPlan != null) {
                    orderInfo.setBatchNo(batchPlan.getBatchNo());
                    log.debug("✅ 批次序号: batchNo={}", batchPlan.getBatchNo());
                }
            } catch (Exception e) {
                log.warn("查询批次序号失败: batchPlanId={}", batch.getBatchPlanId(), e);
            }
        }

// ✅ 查询批次产品列表
        if (batch.getBatchPlanId() != null) {
            try {
                List<ProcessSheetBatchProduct> batchProducts = processSheetBatchProductMapper.selectList(
                        new LambdaQueryWrapper<ProcessSheetBatchProduct>()
                                .eq(ProcessSheetBatchProduct::getBatchId, batch.getBatchPlanId())
                                .eq(ProcessSheetBatchProduct::getIsDeleted, 0)
                );

                if (batchProducts != null && !batchProducts.isEmpty()) {
                    // 批量查询产品详细信息
                    Set<Long> productIds = batchProducts.stream()
                            .map(ProcessSheetBatchProduct::getProductId)
                            .filter(Objects::nonNull)
                            .collect(Collectors.toSet());

                    Map<Long, ProcessSheetProduct> productMap = new HashMap<>();
                    if (!productIds.isEmpty()) {
                        List<ProcessSheetProduct> sheetProducts = processSheetProductMapper.selectBatchIds(new ArrayList<>(productIds));
                        if (sheetProducts != null && !sheetProducts.isEmpty()) {
                            productMap = sheetProducts.stream()
                                    .collect(Collectors.toMap(ProcessSheetProduct::getId, p -> p));
                        }
                    }

                    Map<Long, ProcessSheetProduct> finalProductMap = productMap;
                    List<QualityInspectionDetailVO.BatchProductInfo> productInfos = batchProducts.stream()
                            .map(p -> {
                                QualityInspectionDetailVO.BatchProductInfo info =
                                        new QualityInspectionDetailVO.BatchProductInfo();
                                info.setProductCode(p.getProductCode());
                                info.setProductName(p.getProductName());
                                info.setProductionQuantity(p.getProductionQuantity());

                                // 从工艺单产品获取详细信息
                                if (p.getProductId() != null) {
                                    ProcessSheetProduct sheetProduct = finalProductMap.get(p.getProductId());
                                    if (sheetProduct != null) {
                                        info.setPartDrawingNo(sheetProduct.getPartDrawingNo());
                                        info.setProductHeight(sheetProduct.getProductHeight());
                                        info.setUnitWeight(sheetProduct.getUnitWeight());
                                    }
                                }

                                return info;
                            })
                            .collect(Collectors.toList());

                    orderInfo.setProducts(productInfos);
                    log.debug("✅ 批次产品列表: 产品数量={}", productInfos.size());
                }
            } catch (Exception e) {
                log.warn("查询批次产品列表失败: batchPlanId={}", batch.getBatchPlanId(), e);
            }
        }

        vo.setOrderInfo(orderInfo);

        // ========== 设备信息 ==========
        QualityInspectionDetailVO.DeviceInfo deviceInfo = null;

        // 1. 优先从生产设备字段获取
        if (batch.getDeviceId() != null && StringUtils.isNotBlank(batch.getDeviceName())) {
            deviceInfo = new QualityInspectionDetailVO.DeviceInfo();
            deviceInfo.setDeviceId(batch.getDeviceId().longValue());
            deviceInfo.setDeviceName(batch.getDeviceName());
            deviceInfo.setDeviceCode(batch.getDeviceCode());
            log.debug("使用生产设备: deviceId={}, deviceName={}", batch.getDeviceId(), batch.getDeviceName());
        }
        // 2. 如果生产设备为空，尝试从清洗设备获取
        else if (batch.getCleaningDeviceId() != null && StringUtils.isNotBlank(batch.getCleaningDeviceName())) {
            deviceInfo = new QualityInspectionDetailVO.DeviceInfo();
            deviceInfo.setDeviceId(batch.getCleaningDeviceId());
            deviceInfo.setDeviceName(batch.getCleaningDeviceName());
            log.debug("使用清洗设备: deviceId={}, deviceName={}", batch.getCleaningDeviceId(), batch.getCleaningDeviceName());
        }

        if (deviceInfo != null) {
            vo.setDeviceInfo(deviceInfo);
        }

        // ========== 历史质检记录 ==========
        if (historyRecords != null && !historyRecords.isEmpty()) {
            List<QualityInspectionDetailVO.InspectionHistoryItem> historyItems = historyRecords.stream().map(record -> {
                QualityInspectionDetailVO.InspectionHistoryItem item = new QualityInspectionDetailVO.InspectionHistoryItem();
                item.setInspectionTime(record.getInspectionTime());
                item.setInspectionResult(record.getInspectionResult());
                item.setInspectionResultName(getInspectionResultName(record.getInspectionResult()));
                item.setInspectorName(record.getInspectorName());
                item.setRemark(record.getRemark());
                return item;
            }).collect(java.util.stream.Collectors.toList());
            vo.setInspectionHistory(historyItems);
        }

        log.info("获取质检任务详情成功: taskId={}, stepId={}, userId={}", task.getId(), stepId, userId);
        return vo;
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 获取操作员姓名（从生产操作记录）
     */
    private String getOperatorName(Long stepId) {
        try {
            LambdaQueryWrapper<ProductionOperationRecord> qw = new LambdaQueryWrapper<>();
            qw.eq(ProductionOperationRecord::getStepId, stepId).eq(ProductionOperationRecord::getEventType, "START").eq(ProductionOperationRecord::getIsDelete, 0).orderByDesc(ProductionOperationRecord::getEventTime).last("LIMIT 1");

            ProductionOperationRecord record = productionOperationRecordMapper.selectOne(qw);
            return record != null ? record.getOperatorName() : null;
        } catch (Exception e) {
            log.warn("获取操作员姓名失败: stepId={}", stepId, e);
            return null;
        }
    }

    /**
     * 获取任务状态显示名称
     */
    private String getTaskStatusName(String status) {
        if (status == null) return "";
        switch (status) {
            case "PENDING":
                return "待处理";
            case "IN_PROGRESS":
                return "处理中";
            case "DONE":
                return "已完成";
            default:
                return status;
        }
    }

    /**
     * 获取优先级显示名称
     */
    private String getPriorityName(String priority) {
        if (priority == null) return "普通";
        switch (priority) {
            case "URGENT":
                return "紧急";
            case "NORMAL":
                return "普通";
            case "LOW":
                return "低";
            default:
                return priority;
        }
    }

    /**
     * 获取工序状态显示名称
     */
    private String getStepStatusName(String status) {
        if (status == null) return "";
        switch (status) {
            case "PLANNED":
                return "计划中";
            case "READY":
                return "待开始";
            case "IN_PROGRESS":
                return "进行中";
            case "PENDING_QA":
                return "待质检";
            case "COMPLETED":
                return "已完成";
            default:
                return status;
        }
    }

    /**
     * 获取订单类型显示名称
     */
    private String getOrderTypeName(String orderType) {
        if (orderType == null) return "";
        switch (orderType) {
            case "SALES":
                return "销售订单";
            case "RDO":
                return "研发订单";
            default:
                return orderType;
        }
    }

    /**
     * 获取质检结果显示名称
     */
    private String getInspectionResultName(String result) {
        if (result == null) return "";
        switch (result) {
            case "PASS":
                return "通过";
            case "FAIL":
                return "不通过";
            default:
                return result;
        }
    }


    // ==================== 质检通过 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean qcPass(QualityInspectionRequest request, Long userId, String userName) {
        // 1. 参数校验
        validateRequest(request, "质检通过");

        //   转换 String ID 为 Long
        Long stepId;
        try {
            stepId = Long.parseLong(request.getBatchStepId());
        } catch (NumberFormatException e) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "工序ID格式不正确");
        }

        // 2. 查询工序信息
        ProcessBatchStep step = getProcessBatchStep(stepId);

        // 3. 状态转换前置检查
        StepStatus from = StepStatus.from(step.getStatus());
        if (from == null) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "步骤状态非法");
        }

        StepTransitionContext ctx = new StepTransitionContext();
        if (!stepStateMachine.canTransit(from, StepEvent.QA_PASS, ctx)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "当前步骤不处于待检状态，无法执行质检通过操作（当前状态：" + from.displayName() + "）");
        }

        // 4. 状态转换
        StepStatus next = stepStateMachine.transit(from, StepEvent.QA_PASS, ctx);
        LocalDateTime now = LocalDateTime.now();

        // 5. 更新工序状态
        UpdateWrapper<ProcessBatchStep> uw = new UpdateWrapper<>();
        uw.eq("id", step.getId()).eq("version", step.getVersion()).set("status", next.code()).set("actual_end", now).set("update_time", now).set("version", step.getVersion() + 1);

        if (StringUtils.isNotBlank(request.getRemark())) {
            uw.set("remark", trimAppend(step.getRemark(), " | QA通过: " + request.getRemark()));
        }

        int rows = processBatchStepMapper.update(null, uw);
        if (rows == 0) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "工序状态已被修改，请刷新后重试");
        }

        //   验证更新结果
        ProcessBatchStep updated = processBatchStepMapper.selectById(step.getId());
        log.info("质检通过后工序状态: stepId={}, status={}, actualEnd={}", updated.getId(), updated.getStatus(), updated.getActualEnd());

        if (!"COMPLETED".equals(updated.getStatus())) {
            log.error("❌ 工序状态未正确更新: expected=COMPLETED, actual={}", updated.getStatus());
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "工序状态更新失败");
        }
        log.info("工序质检通过: stepId={}, nextStatus={}, userId={}", step.getId(), next.code(), userId);

        //   转换任务ID
        Long taskId = null;
        if (StringUtils.isNotBlank(request.getTaskId())) {
            try {
                taskId = Long.parseLong(request.getTaskId());
            } catch (NumberFormatException e) {
                log.warn("任务ID格式不正确: {}", request.getTaskId());
            }
        }

        // 6. 保存质检记录
        saveQualityInspectionRecord(step, taskId, "PASS", userId, userName, request.getRemark(), now);

        // 7.   完成质检任务（先尝试认领）
        completeQualityInspectionTask(taskId, userId, userName, request.getRemark());

        // 8. 重新查询最新工序数据，避免使用过期对象
        ProcessBatchStep latestStep = processBatchStepMapper.selectById(step.getId());
        if (latestStep == null || latestStep.getIsDeleted() == 1) {
            log.error("❌ 重新查询工序失败，工序可能已被删除: stepId={}", step.getId());
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "工序数据异常");
        }

        // 9. 检查是否为最后一道工序，完成生产任务
        handleLastStepCompletion(latestStep);

        // 10. 发布质检通过事件（使用最新数据）
        publishQualityPassEvent(latestStep, userId, userName, Objects.toString(request.getRemark(), "检验通过"));

        return true;
    }

    // ==================== 质检不通过 ====================

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean qcFail(QualityInspectionRequest request, Long userId, String userName) {
        // 1. 参数校验
        validateRequest(request, "质检不通过");

        //   质检不通过必须填写原因
        if (StringUtils.isBlank(request.getRemark())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "质检不通过必须填写不合格原因");
        }

        //   转换 String ID 为 Long
        Long stepId;
        try {
            stepId = Long.parseLong(request.getBatchStepId());
        } catch (NumberFormatException e) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "工序ID格式不正确");
        }

        // 2. 查询工序信息
        ProcessBatchStep step = getProcessBatchStep(stepId);

        // 3. 状态转换前置检查
        StepStatus from = StepStatus.from(step.getStatus());
        if (from == null) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "步骤状态非法");
        }

        StepTransitionContext ctx = new StepTransitionContext();
        if (!stepStateMachine.canTransit(from, StepEvent.QA_FAIL, ctx)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "当前步骤不处于待检状态，无法执行质检不通过操作（当前状态：" + from.displayName() + "）");
        }

        // 4. 状态转换（QA_FAIL -> READY，允许返工）
        StepStatus next = stepStateMachine.transit(from, StepEvent.QA_FAIL, ctx);
        LocalDateTime now = LocalDateTime.now();

        // 5. 更新工序状态
        UpdateWrapper<ProcessBatchStep> uw = new UpdateWrapper<>();
        uw.eq("id", step.getId()).eq("version", step.getVersion()).set("status", next.code()).set("update_time", now).set("version", step.getVersion() + 1).set("remark", trimAppend(step.getRemark(), " | QA不通过: " + request.getRemark()));

        int rows = processBatchStepMapper.update(null, uw);
        if (rows == 0) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "工序状态已被修改，请刷新后重试");
        }

        log.info("工序质检不通过: stepId={}, nextStatus={}, userId={}, reason={}", step.getId(), next.code(), userId, request.getRemark());

        //   转换任务ID
        Long taskId = null;
        if (StringUtils.isNotBlank(request.getTaskId())) {
            try {
                taskId = Long.parseLong(request.getTaskId());
            } catch (NumberFormatException e) {
                log.warn("任务ID格式不正确: {}", request.getTaskId());
            }
        }

        // 6. 保存质检记录
        saveQualityInspectionRecord(step, taskId, "FAIL", userId, userName, request.getRemark(), now);

        // 7.   完成质检任务
        completeQualityInspectionTask(taskId, userId, userName, request.getRemark());

        // 8.   创建返工任务，通知生产部
        createReworkTask(step, request.getRemark(), userId, userName);

        // 9. 发布质检失败事件
        publishQualityFailEvent(step, userId, userName, request.getRemark());

        return true;
    }
    // ==================== 私有辅助方法 ====================

    /**
     * 参数校验
     */
    private void validateRequest(QualityInspectionRequest request, String operation) {
        if (request == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, operation + "参数不能为空");
        }
        //   现在 batchStepId 是 String，可以用 StringUtils.isBlank()
        if (StringUtils.isBlank(request.getBatchStepId())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, operation + "参数不合法：工序ID不能为空");
        }
    }

    /**
     * 查询并校验工序信息
     */
    private ProcessBatchStep getProcessBatchStep(Long stepId) {
        ProcessBatchStep step = processBatchStepMapper.selectById(stepId);
        if (step == null || (step.getIsDeleted() != null && step.getIsDeleted() == 1)) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "工序不存在或已被删除");
        }
        return step;
    }

    /**
     * 完成质检任务（优化：增加幂等性检查）
     */
    private void completeQualityInspectionTask(Long taskId, Long userId, String userName, String remark) {
        if (taskId == null) {
            log.warn("质检任务ID为空，跳过任务完成操作");
            return;
        }

        try {
            // 查询任务
            WorkflowTask task = workflowTaskMapper.selectById(taskId);
            if (task == null || task.getIsDelete() == 1) {
                log.warn("质检任务不存在或已删除: taskId={}", taskId);
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "质检任务不存在");
            }

            // 幂等性检查：任务已完成则直接返回
            if ("DONE".equals(task.getTaskStatus())) {
                log.info("质检任务已完成，跳过重复操作: taskId={}, completedBy={}", taskId, task.getClaimedByName());
                return;
            }

            // 先尝试认领（如果部门要求认领）
            if (task.getClaimedBy() == null) {
                log.info("质检任务未认领，尝试自动认领: taskId={}, userId={}", taskId, userId);
                workflowTaskService.claimTask(taskId, userId, userName, null);
            }

            // 完成任务
            boolean completed = workflowTaskService.completeTask(taskId, userId, userName, remark);
            if (!completed) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "质检任务完成失败，请检查任务状态（taskId=" + taskId + "）");
            }

            log.info("质检任务完成成功: taskId={}, userId={}", taskId, userId);

        } catch (BusinessException e) {
            // 业务异常直接抛出
            throw e;
        } catch (Exception e) {
            log.error("完成质检任务失败: taskId={}, userId={}", taskId, userId, e);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "完成质检任务失败: " + e.getMessage());
        }
    }

    /**
     * 优化：处理最后一道工序完成后的生产任务完成逻辑
     */
    private void handleLastStepCompletion(ProcessBatchStep currentStep) {
        // 1. 查询下一道工序
        LambdaQueryWrapper<ProcessBatchStep> nextQw = new LambdaQueryWrapper<>();
        nextQw.eq(ProcessBatchStep::getBatchId, currentStep.getBatchId()).eq(ProcessBatchStep::getSequenceNo, currentStep.getSequenceNo() + 1).eq(ProcessBatchStep::getIsDeleted, 0).last("LIMIT 1");
        ProcessBatchStep nextStep = processBatchStepMapper.selectOne(nextQw);

        boolean isLastProcess = (nextStep == null);

        if (isLastProcess) {
            log.info("⏹️ 当前工序是最后一道工序，准备完成生产任务并创建检验报告待办: stepId={}, batchId={}",
                    currentStep.getId(), currentStep.getBatchId());

            // 2. 完成生产工单任务（统一调用任务操作服务）
            boolean taskCompleted = workflowTaskOperationService.completeProductionWorkorderTaskIfAllStepsFinished(
                    currentStep.getBatchId(),
                    "所有工序已完成（含质检）"
            );

            if (!taskCompleted) {
                log.warn("⚠️ 生产工单任务完成失败或不存在: batchId={}", currentStep.getBatchId());
                return;
            }

            // 3. 查询生产工单任务（获取订单信息用于创建检验报告）
            LambdaQueryWrapper<WorkflowTask> taskQw = new LambdaQueryWrapper<>();
            taskQw.eq(WorkflowTask::getBizType, "PROCESS_BATCH")
                    .eq(WorkflowTask::getBizId, currentStep.getBatchId())
                    .eq(WorkflowTask::getTaskType, "PRODUCTION_WORKORDER")
                    .eq(WorkflowTask::getIsDelete, 0)
                    .last("LIMIT 1");
            WorkflowTask productionTask = workflowTaskMapper.selectOne(taskQw);

            if (productionTask == null) {
                log.warn("⚠️ 未找到生产工单任务，无法获取订单信息: batchId={}", currentStep.getBatchId());
                return;
            }

            // ========== ✅ 核心修复：创建检验报告待办 ==========
            try {
                // 获取订单信息
                String orderNumber = productionTask.getBizNumber();
                String productName = productionTask.getProductName();
                // ... 后续逻辑

                // 获取当前操作员信息（质检员）
                Long creatorId = null;
                String creatorName = "系统自动";

                // 尝试从最近的质检记录获取操作员信息
                LambdaQueryWrapper<QualityInspectionRecord> qirQw = new LambdaQueryWrapper<>();
                qirQw.eq(QualityInspectionRecord::getStepId, currentStep.getId()).orderByDesc(QualityInspectionRecord::getInspectionTime).last("LIMIT 1");
                QualityInspectionRecord lastRecord = qualityInspectionRecordMapper.selectOne(qirQw);

                if (lastRecord != null) {
                    creatorId = lastRecord.getInspectorId();
                    creatorName = lastRecord.getInspectorName();
                }

                // 创建检验报告任务（按工艺单维度，需全部批次完成）
                try {
                    // 获取当前批次与工艺单ID
                    ProcessBatch currentBatch = processBatchMapper.selectById(currentStep.getBatchId());
                    if (currentBatch == null) {
                        log.warn("未找到批次，无法创建检验报告任务: batchId={}", currentStep.getBatchId());
                        return;
                    }
                    Long processSheetId = currentBatch.getProcessSheetId();

                    //   检查该工艺单下是否所有批次均已完成（不依赖批次状态）
                    boolean allBatchesCompleted = checkAllBatchesCompleted(processSheetId);
                    if (!allBatchesCompleted) {
                        log.info("工艺单尚有未完成批次，暂不创建检验报告任务: processSheetId={}", processSheetId);
                        return;
                    }

                    log.info("🚀 开始创建检验报告任务: processSheetId={}, orderNumber={}, creatorName={}", processSheetId, orderNumber, creatorName);

                    taskCreationService.createInspectionReportTask(processSheetId, orderNumber, productName, creatorId, creatorName);

                    log.info("  检验报告任务创建成功: processSheetId={}, orderNumber={}", processSheetId, orderNumber);

                } catch (Exception e) {
                    log.error("❌ 创建检验报告任务失败: batchId={}", currentStep.getBatchId(), e);

                    try {
                        Map<String, Object> errorPayload = new HashMap<>();
                        errorPayload.put("batchId", currentStep.getBatchId());
                        errorPayload.put("stepId", currentStep.getId());
                        errorPayload.put("errorMessage", e.getMessage());
                        errorPayload.put("errorTime", LocalDateTime.now());

                        outboxService.enqueue(null, "quality.report.creation.failed", "quality.report.creation.failed", errorPayload);

                        log.info("📨 已发布检验报告创建失败事件，可手动补偿");
                    } catch (Exception ex) {
                        log.error("记录检验报告创建失败事件时出错", ex);
                    }
                }
            } catch (Exception e) {
                log.error("❌ 创建检验报告任务失败: batchId={}", currentStep.getBatchId(), e);

                //   记录失败事件，便于后续补偿
                try {
                    Map<String, Object> errorPayload = new HashMap<>();
                    errorPayload.put("batchId", currentStep.getBatchId());
                    errorPayload.put("stepId", currentStep.getId());
                    errorPayload.put("errorMessage", e.getMessage());
                    errorPayload.put("errorTime", LocalDateTime.now());

                    outboxService.enqueue(null, "quality.report.creation.failed", "quality.report.creation.failed", errorPayload);

                    log.info("📨 已发布检验报告创建失败事件，可手动补偿");
                } catch (Exception ex) {
                    log.error("记录检验报告创建失败事件时出错", ex);
                }

                // ⚠️ 不影响主流程，只记录日志
            }

        } else {
            log.info("➡️ 当前工序不是最后一道，下一道工序: nextStepId={}, stepNo={}", nextStep.getId(), nextStep.getSequenceNo());
        }
    }

    /**
     * 创建返工任务
     */
    private void createReworkTask(ProcessBatchStep step, String failReason, Long creatorId, String creatorName) {
        try {
            // 获取订单编号
            String orderNumber = getOrderNumberFromBatch(step.getBatchId());

            // 调用任务创建服务
            taskCreationService.createReworkTask(step.getId(), step.getBatchId(), orderNumber, step.getOperationName(), failReason, creatorId, creatorName);

            log.info("返工任务创建成功: stepId={}, stepName={}", step.getId(), step.getOperationName());

        } catch (Exception e) {
            log.error("创建返工任务失败: stepId={}", step.getId(), e);
            // 返工任务创建失败不影响主流程，记录日志即可
        }
    }

    /**
     * 保存质检记录
     */
    private void saveQualityInspectionRecord(ProcessBatchStep step, Long taskId, String result, Long userId, String userName, String remark, LocalDateTime inspectionTime) {
        try {
            QualityInspectionRecord record = new QualityInspectionRecord();
            record.setTaskId(taskId);
            record.setStepId(step.getId());
            record.setBatchId(step.getBatchId());
            record.setInspectorId(userId);
            record.setInspectorName(userName);
            record.setInspectionResult(result);
            record.setRemark(remark);
            record.setInspectionTime(inspectionTime);
            record.setCreateTime(LocalDateTime.now());
            record.setUpdateTime(LocalDateTime.now());

            qualityInspectionRecordService.saveInspectionRecord(record);
        } catch (Exception e) {
            log.error("保存质检记录失败: stepId={}, result={}", step.getId(), result, e);
            // 记录保存失败不影响主流程
        }
    }

    /**
     * 发布质检通过事件
     */
    private void publishQualityPassEvent(ProcessBatchStep step, Long userId, String userName, String remark) {
        publishEvent(step, "quality.inspection.passed", userId, userName, remark);
    }

    /**
     * 发布质检失败事件
     */
    private void publishQualityFailEvent(ProcessBatchStep step, Long userId, String userName, String remark) {
        try {
            Map<String, Object> payload = new HashMap<>();
            payload.put("batchStepId", step.getId());
            payload.put("batchId", step.getBatchId());
            payload.put("operationName", step.getOperationName());
            payload.put("status", step.getStatus());
            payload.put("remark", remark);
            payload.put("operatorId", userId);
            payload.put("operatorName", userName);
            payload.put("time", LocalDateTime.now());
            payload.put("orderNumber", getOrderNumberFromBatch(step.getBatchId()));

            outboxService.enqueue(null, "quality.inspection.failed", "quality.inspection.failed", payload);
        } catch (Exception e) {
            log.warn("发布质检失败事件失败: stepId={}", step.getId(), e);
        }
    }

    /**
     * 发布事件
     */
    private void publishEvent(ProcessBatchStep step, String routingKey, Long userId, String userName, String remark) {
        try {
            Map<String, Object> payload = new HashMap<>();
            payload.put("batchStepId", step.getId());
            payload.put("batchId", step.getBatchId());
            payload.put("operationName", step.getOperationName());
            payload.put("status", step.getStatus());
            payload.put("remark", remark);
            payload.put("operatorId", userId);
            payload.put("operatorName", userName);
            payload.put("time", LocalDateTime.now());
            outboxService.enqueue(null, routingKey, routingKey, payload);
        } catch (Exception e) {
            log.warn("发布品质事件失败: stepId={}, rk={}", step.getId(), routingKey, e);
        }
    }

    /**
     * 追加备注
     */
    private String trimAppend(String original, String suffix) {
        String base = original == null ? "" : original.trim();
        return base.isEmpty() ? suffix : (base + suffix);
    }

    /**
     * 从批次获取订单编号（辅助方法）
     */
    private String getOrderNumberFromBatch(Long batchId) {
        // 实现略：查询 ProcessBatch 表获取 orderNumber
        // 这里简化处理，返回批次ID
        return "BATCH-" + batchId;
    }

    /**
     * 检查工艺单的所有批次是否都完成（不依赖批次状态，直接检查工序）
     *
     * @param processSheetId 工艺单ID
     * @return true-所有批次都完成, false-仍有未完成批次
     */
    private boolean checkAllBatchesCompleted(Long processSheetId) {
        if (processSheetId == null) {
            log.warn("checkAllBatchesCompleted: processSheetId 为空");
            return false;
        }

        // 1. 查询该工艺单的所有批次
        List<ProcessBatch> batches = processBatchMapper.selectList(new LambdaQueryWrapper<ProcessBatch>().eq(ProcessBatch::getProcessSheetId, processSheetId).eq(ProcessBatch::getIsDeleted, 0));

        if (batches == null || batches.isEmpty()) {
            log.warn("工艺单无批次数据: processSheetId={}", processSheetId);
            return false;
        }

        log.info("开始检查工艺单批次完成情况: processSheetId={}, 批次数={}", processSheetId, batches.size());

        // 2. 检查每个批次的所有工序是否都完成
        for (ProcessBatch batch : batches) {
            // 查询该批次的所有工序
            List<ProcessBatchStep> steps = processBatchStepMapper.selectList(
                    new LambdaQueryWrapper<ProcessBatchStep>()
                            .eq(ProcessBatchStep::getBatchId, batch.getId())
                            .eq(ProcessBatchStep::getIsDeleted, 0)
            );

            if (steps == null || steps.isEmpty()) {
                log.warn("批次无工序数据: batchId={}, batchCode={}", batch.getId(), batch.getBatchCode());
                return false;
            }

            // 统计完成情况
            long totalSteps = steps.size();
            long completedSteps = steps.stream()
                    .filter(s -> "COMPLETED".equals(s.getStatus()))
                    .count();

            log.info("批次 {} 工序完成情况: {}/{}", batch.getBatchCode(), completedSteps, totalSteps);

            // 检查是否所有工序都完成
            if (completedSteps < totalSteps) {
                log.info("批次尚有未完成工序: batchId={}, batchCode={}, 未完成工序数={}",
                        batch.getId(), batch.getBatchCode(), totalSteps - completedSteps);
                return false;
            }

            // ✅ 所有工序都完成，调用统一的批次状态更新服务
            try {
                processBatchService.updateBatchStatusIfCompleted(batch.getId());
            } catch (Exception e) {
                log.warn("⚠️ 更新批次状态失败（不影响主流程）: batchId={}, batchCode={}",
                        batch.getId(), batch.getBatchCode(), e);
                // 不抛出异常，继续检查
            }
        }

        // 3. 所有批次都完成
        log.info("  工艺单的所有批次都已完成: processSheetId={}, 批次数={}", processSheetId, batches.size());
        return true;
    }
}